package com.wumai.modernguilib.panel;

import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.systems.RenderSystem;
import com.wumai.modernguilib.component.BaseComponent;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.AbstractGui;

public class ScrollablePanel extends BaseView {
    protected float itemHeight;  // 改为float类型
    protected float itemSpacing; // 改为float类型
    protected boolean scrolling = false;

    private int scrollBarY = 0;
    private int scrollBarHeight = 0;
    private float scrollBarRate = 0;
    private float scrollBarMinHeight = 0.005f;
    private float scrollBarBackGroundwidth = 0.01f;
    private double scrollLastMouseY = 0;
    private int currentContentHeight = 0;

    /**
     * 之前这里是int，但是这样的话，在更新此值的方法中，赋值时转换了int，导致精度丢失，
     * 微小的变动被忽略了，改成double之后，仅仅在render时转换了，微小的变化被积累了下来
     * [11:47:45] [Render thread/INFO] [STDOUT/]: [com.wumai.modernguilib.panel.ScrollablePanel:updateScrollOffset:83]: scrollOffset:-17.5546875
     * [11:47:45] [Render thread/INFO] [STDOUT/]: [com.wumai.modernguilib.panel.ScrollablePanel:updateScrollOffset:83]: scrollOffset:-16.71875
     * [11:47:45] [Render thread/INFO] [STDOUT/]: [com.wumai.modernguilib.panel.ScrollablePanel:updateScrollOffset:83]: scrollOffset:-15.8828125
     * [11:47:45] [Render thread/INFO] [STDOUT/]: [com.wumai.modernguilib.panel.ScrollablePanel:updateScrollOffset:83]: scrollOffset:-15.046875
     * [11:47:45] [Render thread/INFO] [STDOUT/]: [com.wumai.modernguilib.panel.ScrollablePanel:updateScrollOffset:83]: scrollOffset:-14.2109375
     * [11:47:45] [Render thread/INFO] [STDOUT/]: [com.wumai.modernguilib.panel.ScrollablePanel:updateScrollOffset:83]: scrollOffset:-13.375
     * */
    private double scrollOffset = 0;

    public ScrollablePanel(float itemHeight, float itemSpacing) {
        // 新的构造函数，不指定位置和大小，将自动填充屏幕
        super(0, 0, 0, 0); // NDC坐标系中填充整个屏幕
        this.itemHeight = itemHeight;
        this.itemSpacing = itemSpacing;
    }

    public ScrollablePanel(int x, int y, int width, int height, float itemHeight, float itemSpacing) {
        super(x, y, width, height);
        this.itemHeight = itemHeight;
        this.itemSpacing = itemSpacing;
    }

    @Override
    protected void renderBackground(MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks) {

        // 绘制半透明背景
        AbstractGui.fill(matrixStack, x, y, x + width, y + height, 0x80000000);

        // 绘制边框
        AbstractGui.fill(matrixStack, x, y, x + width, y + 1, 0xFFFFFFFF); // 上边框
        AbstractGui.fill(matrixStack, x, y + height - 1, x + width, y + height, 0xFFFFFFFF); // 下边框
        AbstractGui.fill(matrixStack, x, y, x + 1, y + height, 0xFFFFFFFF); // 左边框
        AbstractGui.fill(matrixStack, x + width - 1, y, x + width, y + height, 0xFFFFFFFF); // 右边框
    }

    @Override
    protected void renderContent(MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks) {
        AbstractGui.fill(matrixStack, x + width - (int)(scrollBarBackGroundwidth * getCurrentScreenWidth()), scrollBarY, x + width, scrollBarY + scrollBarHeight, 0xFFFFFFFF);
    }

    public void updateLayout() {
        // 更新滚动条
        updateScrollBar();
        // 这里和addChild时更新的组件范围不同，当一个子组件被添加到这个父组件时
        // 只需更新这个子组件的位置大小
        // 而当这个组件被添加到另外一个容器里时，就要调用这个方法更新其内部所有子组件
        int currentY = this.y + (int)(paddings[PaddingPosition.TOP] * getCurrentScreenHeight()) + (int)scrollOffset;
        int beginY = currentY;
        for (BaseComponent child : children) {
            child.setX(this.x + (int)(paddings[PaddingPosition.LEFT] * getCurrentScreenWidth()));
            child.setY(currentY);
            child.setWidth(this.width - (int)(paddings[PaddingPosition.LEFT] * getCurrentScreenWidth()) - (int)(paddings[PaddingPosition.RIGHT] * getCurrentScreenWidth()) - (int)(scrollBarBackGroundwidth * getCurrentScreenWidth()));
            child.setHeight((int)(itemHeight * getCurrentScreenHeight()) - (int)(paddings[PaddingPosition.TOP] * getCurrentScreenHeight()) - (int) (paddings[PaddingPosition.BOTTOM] * getCurrentScreenHeight()));

            // 实际上这里还要根据实际的

            currentY += (int)(itemHeight * getCurrentScreenHeight()) + (int) (paddings[PaddingPosition.BOTTOM] * getCurrentScreenHeight()) + (int)(itemSpacing * getCurrentScreenHeight()) + (int)(paddings[PaddingPosition.TOP] * getCurrentScreenHeight());
        }
        currentContentHeight = currentY - beginY - (int)(itemSpacing * getCurrentScreenHeight()) - (int)(paddings[PaddingPosition.TOP] * getCurrentScreenHeight());
    }


    private void updateScrollOffset(double delta) {
        // 先判断边界条件，如果超出范围，就移动到边界
        if (-scrollOffset + (delta) * scrollBarRate < 0) {
            scrollOffset = 0;
            return;
        }
        if (-scrollOffset + (delta) * scrollBarRate > currentContentHeight - height) {
            scrollOffset = -(currentContentHeight - height);
            return;
        }
        // 除开边界情况，就要计算偏移量了
        System.out.println("scrollOffset:" + scrollOffset);
        scrollOffset += (-(delta) * scrollBarRate);
    }

    @Override
    public boolean mouseClicked(double mouseX, double mouseY, int button) {
        // 不在这个组件范围内的点击事件不由本组件处理
        if (!super.isMouseOver(mouseX, mouseY)) {
            return false;
        }
        // 判断是否在滚动条区域内, 且需要滚动时
        if (mouseX >= x + width - (int)(scrollBarBackGroundwidth * getCurrentScreenWidth()) &&
                mouseX < x + width && mouseY >= y && mouseY < y + height &&
                height != scrollBarHeight) {
            if (mouseY >= scrollBarY && mouseY < scrollBarY + scrollBarHeight) {
                if (!scrolling) {
                    scrolling = true;
                    scrollLastMouseY = mouseY;
                    return true;
                }
            } else {
                if (!scrolling) {
                    // 没有点击过滚动条也不在滚动条区域内，表示第一次点击时，在别的位置
                    // 直接将滚动条中间位置的Y赋值给scrollLastMouseY，作为上一次的位置，进行位置更新
                    // 再按照实际偏移量更新滚动条位置
                    updateScrollOffset(mouseY - (scrollBarY + (double) scrollBarHeight / 2));
                    onParentLayoutChanged();
                    return true;
                }
            }
        }
        return super.mouseClicked(mouseX, mouseY, button);
    }

    @Override
    public boolean mouseReleased(double mouseX, double mouseY, int button) {
        // 鼠标释放，清除所有状态变量即可
        scrolling = false;
        scrollLastMouseY = 0;
        // 不在这个组件范围内的点击事件不由本组件处理，但是状态还是要清除
        if (!super.isMouseOver(mouseX, mouseY)) {
            return false;
        }
        return super.mouseReleased(mouseX, mouseY, button);
    }

    @Override
    public boolean mouseScrolled(double mouseX, double mouseY, double delta) {
        if (super.isMouseOver(mouseX, mouseY)) {
            updateScrollOffset(-delta * 3.0);
            onParentLayoutChanged();
            return true;
        }
        return false;
    }

    // ScrollablePanel.java
    @Override
    protected void onBeforeRender(MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks) {
        isMouseOver(mouseX, mouseY);

        // 保存当前的裁剪区域
        double scale = Minecraft.getInstance().getWindow().getGuiScale();
        int originalScissorX = (int) (x * scale);
        int originalScissorY = (int) (Minecraft.getInstance().getWindow().getHeight() - (y + height) * scale);
        int originalScissorWidth = (int) (width * scale);
        int originalScissorHeight = (int) (height * scale);

        // 滚动条渲染
        AbstractGui.fill(matrixStack, x + width - (int)(scrollBarBackGroundwidth * getCurrentScreenWidth()),
                scrollBarY, x + width, scrollBarY + scrollBarHeight, 0xFFFFFFFF);

        // 启用裁剪并设置裁剪区域
        RenderSystem.enableScissor(originalScissorX, originalScissorY, originalScissorWidth, originalScissorHeight);
    }

    @Override
    protected void onAfterRender(MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks) {
        // 禁用裁剪
        RenderSystem.disableScissor();
    }


//    @Override
//    public void render(MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks) {
//
//        isMouseOver(mouseX, mouseY);
//
//        // 保存当前的裁剪区域
//        double scale = Minecraft.getInstance().getWindow().getGuiScale();
//        int originalScissorX = (int) (x * scale);
//        int originalScissorY = (int) (Minecraft.getInstance().getWindow().getHeight() - (y + height) * scale);
//        int originalScissorWidth = (int) (width * scale);
//        int originalScissorHeight = (int) (height * scale);
//
//        // 滚动条渲染
//        AbstractGui.fill(matrixStack, x + width - (int)(scrollBarBackGroundwidth * getCurrentScreenWidth()), scrollBarY, x + width, scrollBarY + scrollBarHeight, 0xFFFFFFFF);
//
//        // 启用裁剪并设置裁剪区域
//        RenderSystem.enableScissor(originalScissorX, originalScissorY, originalScissorWidth, originalScissorHeight);
//
//        // 渲染背景
//        renderBackground(matrixStack);
//
//        // 渲染子组件（只有在裁剪区域内的部分才会显示）
//        for (BaseComponent child : children) {
//            // 可以添加额外的可见性检查来提高性能
//            if (isItemVisible(child)) {
//                child.render(matrixStack, mouseX, mouseY, partialTicks);
//            }
////            child.render(matrixStack, mouseX, mouseY, partialTicks);
//        }
//
//        // 禁用裁剪
//        RenderSystem.disableScissor();
//    }

//    @Override
//    public boolean mouseDragged(double mouseX, double mouseY, int button, double dragX, double dragY) {
//        // 面板一般不处理事件，如果要处理就要重写，既然重写就要重新添加逻辑
////        if (mouseX >= x + width - (int)(scrollBarBackGroundwidth * getCurrentScreenWidth()) &&
////                mouseX < x + width && mouseY >= y && mouseY < y + height &&
////                scrollBarHeight != height
////        ) {
////            updateScrollOffset(dragY);
////            onParentLayoutChanged();
////            return true;
////        }
//
//        return super.mouseDragged(mouseX, mouseY, button, dragX, dragY);
//    }

    @Override
    public boolean mouseDragged(double mouseX, double mouseY, int button, double dragX, double dragY) {
        if (scrolling) {
            updateScrollOffset(mouseY - scrollLastMouseY);
            onParentLayoutChanged();
            scrollLastMouseY = mouseY;
            return true;
        }
        return super.mouseDragged(mouseX, mouseY, button, dragX, dragY);
    }

    private void updateScrollBar() {
        // 当内容高度小于面板高度时，滚动条和容器同高，此时不需要更新任何东西
        if (currentContentHeight <= height) {
            scrollBarHeight = height;
            return;
        }
        // 当内容高度大于面板高度直至使得滚动条小于最小大小时，为最小大小
        if ((float) height / currentContentHeight < scrollBarMinHeight * getCurrentScreenHeight() / height) {
            scrollBarHeight = (int)(scrollBarMinHeight * getCurrentScreenHeight());
        }
        // 其他情况滚动条大小根据实际情况进行计算
        scrollBarHeight = (int)((float) height / currentContentHeight * height);
        // 根据滚动条大小、容器高度、实际内容高度计算出滚动条Rate，也就是滚动条移动一个像素，内容移动多少
        scrollBarRate = (float) (currentContentHeight - height) / (height - scrollBarHeight);
        // 根据实际内容偏移量计算出滚动条偏移量
        scrollBarY = y + (int)((-scrollOffset) / scrollBarRate);
    }

    private boolean isItemVisible(BaseComponent item) {
        // 检查项目是否在可视区域内
        return item.getY() + item.getHeight() > y && item.getY() < y + height;
    }
    
    /**
     * 当组件被添加到可滚动面板时，自动计算其位置和大小
     * @param parent 父容器
     */
    @Override
    public void onAddedToParent(BaseComponent parent) {

    }

    @Override
    public void setY(int y) {
        this.y = y;
        this.scrollBarY = y;
    }

    public float getItemHeight() {
        return itemHeight;
    }

    public void setItemHeight(float itemHeight) {
        this.itemHeight = itemHeight;
    }

    public float getItemSpacing() {
        return itemSpacing;
    }

    public void setItemSpacing(float itemSpacing) {
        this.itemSpacing = itemSpacing;
    }
    
    /**
     * 从面板中移除指定的列表项
     * @param item 要移除的列表项
     * @return 是否成功移除
     */
    public boolean removeItem(ScrollableListItem item) {
        return children.remove(item);
    }
    
    /**
     * 移除指定位置的列表项
     * @param index 要移除的项的索引
     * @return 被移除的列表项
     */
    public BaseComponent removeItem(int index) {
        return children.remove(index);
    }
    
    /**
     * 清空所有列表项
     */
    public void clearItems() {
        children.clear();
    }

    public abstract static class ScrollableListItem extends BaseView {
        protected boolean isSelected = false;
        protected boolean isHovered = false;

        public ScrollableListItem(int width, int height) {
            super(0, 0, width, height); // x, y will be managed by the parent panel
        }

        public ScrollableListItem(){
            super();
        }

        public void updateLayout() {
            for (BaseComponent child : children) {
                child.setX(x + (int)(paddings[PaddingPosition.LEFT] * getCurrentScreenWidth()));
                child.setY(y + (int)(paddings[PaddingPosition.TOP] * getCurrentScreenHeight()));
                child.setWidth(width - (int)(paddings[PaddingPosition.LEFT] * getCurrentScreenWidth()) - (int)(paddings[PaddingPosition.RIGHT] * getCurrentScreenWidth()));
                child.setHeight(height - (int)(paddings[PaddingPosition.TOP] * getCurrentScreenHeight()) - (int)(paddings[PaddingPosition.BOTTOM] * getCurrentScreenHeight()));
            }
        }
        protected abstract void renderContent(MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks);

        public void onClicked(int button) {
            // 默认实现为空，子类可以重写
        }

        public void onReleased(int button) {
            // 默认实现为空，子类可以重写
        }

        public boolean isSelected() {
            return isSelected;
        }

        public void setSelected(boolean selected) {
            isSelected = selected;
        }

        public boolean isHovered() {
            return isHovered;
        }
    }
}